#include "ST7789.h"
#include "spi.h"
#include "dma.h"
#include "tim.h"

static uint16_t _width = ST7789_TFTWIDTH;
static uint16_t _height = ST7789_TFTHEIGHT;
static uint8_t rotation = ST7789_ROTATION_0;
static void (*drwa_window_cplt_cb)(void) = NULL;

void st7789_send_cmd(uint8_t cmd)
{
    ST7789_PORT_CS_SELECT();

    ST7789_CMD(true);
    st7789_spi_tx_byte(cmd);

    ST7789_PORT_CS_DISELECT();
}
void st7789_send_half_word(uint16_t data)
{
    ST7789_PORT_CS_SELECT();

    ST7789_DATA(true);
    st7789_spi_tx_half_word(data);

    ST7789_PORT_CS_DISELECT();
}
void st7789_send_byte(uint8_t data)
{
    ST7789_PORT_CS_SELECT();

    ST7789_DATA(true);
    st7789_spi_tx_byte(data);

    ST7789_PORT_CS_DISELECT();
}

void st7789_send_dma(uint16_t *color, uint16_t len)
{
    ST7789_PORT_CS_SELECT();
    ST7789_DATA(true);
    st7789_spi_tx_dma(color, len);
}

void st7789_dma_cplt_cb(void)
{
    if (drwa_window_cplt_cb)
    {
        drwa_window_cplt_cb();
    }
    ST7789_PORT_CS_DISELECT();
}

void st7789_drwa_window_cplt_register_cb(void (*fun)(void))
{
    drwa_window_cplt_cb = fun;
}

bool st7789_init(void)
{

    st7789_spi_init();

    MX_DMA_Register_IT_Cb(MC_DMA_CB_ID_ST7789, MX_DMA_CB_TYPE_CPLT, st7789_dma_cplt_cb);
    /*TFT复位*/
    ST7789_RST_CLR();
    ST7789_DELAY(200);
    ST7789_RST_SET();
    ST7789_DELAY(300);

    //************* Start Initial Sequence **********//
    st7789_send_cmd(0x36);
    st7789_send_byte(0x00);

    st7789_send_cmd(0x3A);
    st7789_send_byte(0x05);

    st7789_send_cmd(0xB2);
    st7789_send_byte(0x0C);
    st7789_send_byte(0x0C);
    st7789_send_byte(0x00);
    st7789_send_byte(0x33);
    st7789_send_byte(0x33);

    st7789_send_cmd(0xB7);
    st7789_send_byte(0x35);

    st7789_send_cmd(0xBB);
    st7789_send_byte(0x19);

    st7789_send_cmd(0xC0);
    st7789_send_byte(0x2C);

    st7789_send_cmd(0xC2);
    st7789_send_byte(0x01);

    st7789_send_cmd(0xC3);
    st7789_send_byte(0x12);

    st7789_send_cmd(0xC4);
    st7789_send_byte(0x20);

    st7789_send_cmd(0xC6);
    st7789_send_byte(0x0F);

    st7789_send_cmd(0xD0);
    st7789_send_byte(0xA4);
    st7789_send_byte(0xA1);

    st7789_send_cmd(0xE0);
    st7789_send_byte(0xD0);
    st7789_send_byte(0x04);
    st7789_send_byte(0x0D);
    st7789_send_byte(0x11);
    st7789_send_byte(0x13);
    st7789_send_byte(0x2B);
    st7789_send_byte(0x3F);
    st7789_send_byte(0x54);
    st7789_send_byte(0x4C);
    st7789_send_byte(0x18);
    st7789_send_byte(0x0D);
    st7789_send_byte(0x0B);
    st7789_send_byte(0x1F);
    st7789_send_byte(0x23);

    st7789_send_cmd(0xE1);
    st7789_send_byte(0xD0);
    st7789_send_byte(0x04);
    st7789_send_byte(0x0C);
    st7789_send_byte(0x11);
    st7789_send_byte(0x13);
    st7789_send_byte(0x2C);
    st7789_send_byte(0x3F);
    st7789_send_byte(0x44);
    st7789_send_byte(0x51);
    st7789_send_byte(0x2F);
    st7789_send_byte(0x1F);
    st7789_send_byte(0x1F);
    st7789_send_byte(0x20);
    st7789_send_byte(0x23);

    st7789_send_cmd(0x21);

    st7789_send_cmd(0x11);

    st7789_send_cmd(0x29);
}

void st7789_set_blk(uint16_t val)
{
    HAL_TIM_Base_Set_CH3_PWM_Duty(val);
}

uint16_t st7789_get_width(void)
{
    return _width;
}

uint16_t st7789_get_height(void)
{
    return _height;
}

void st7789_rotation(uint8_t r)
{
    rotation = r % 4;
    switch (rotation)
    {
    case 0:
        _width = ST7789_TFTWIDTH;
        _height = ST7789_TFTHEIGHT;

        st7789_send_cmd(0x36);
        st7789_send_byte(0x00);
        break;

    case 1:
        _width = ST7789_TFTHEIGHT;
        _height = ST7789_TFTWIDTH;

        st7789_send_cmd(0x36);
        st7789_send_byte(0xA0);
        break;

    case 2:
        _width = ST7789_TFTWIDTH;
        _height = ST7789_TFTHEIGHT;

        st7789_send_cmd(0x36);
        st7789_send_byte(0xC0);
        break;

    case 3:
        _width = ST7789_TFTHEIGHT;
        _height = ST7789_TFTWIDTH;

        st7789_send_cmd(0x36);
        st7789_send_byte(0x70);
        break;
    }
}

void st7789_drwa_window(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t *color)
{
    uint16_t height;
    uint16_t width;

    switch (rotation)
    {
    case 0:
        st7789_send_cmd(0x2A);
        st7789_send_half_word(x0 + 52);
        st7789_send_half_word(x1 + 52);

        st7789_send_cmd(0x2B);
        st7789_send_half_word(y0 + 40);
        st7789_send_half_word(y1 + 40);

        st7789_send_cmd(0x2C);
        break;

    case 1:
        st7789_send_cmd(0x2A);
        st7789_send_half_word(x0 + 40);
        st7789_send_half_word(x1 + 40);

        st7789_send_cmd(0x2B);
        st7789_send_half_word(y0 + 52);
        st7789_send_half_word(y1 + 52);

        st7789_send_cmd(0x2C);
        break;

    case 2:
        st7789_send_cmd(0x2A);
        st7789_send_half_word(x0 + 53);
        st7789_send_half_word(x1 + 53);

        st7789_send_cmd(0x2B);
        st7789_send_half_word(y0 + 40);
        st7789_send_half_word(y1 + 40);

        st7789_send_cmd(0x2C);
        break;

    case 3:
        st7789_send_cmd(0x2A);
        st7789_send_half_word(x0 + 40);
        st7789_send_half_word(x1 + 40);

        st7789_send_cmd(0x2B);
        st7789_send_half_word(y0 + 52);
        st7789_send_half_word(y1 + 52);

        st7789_send_cmd(0x2C);
        break;
    }

    height = abs(y1 - y0) + 1;
    width = abs(x1 - x0) + 1;
    st7789_send_dma(color, height * width);
}

void st7789_fillScreen(uint16_t color)
{
    st7789_drwa_window(0, 0, _width - 1, _height - 1, 0);
    uint32_t size = _width * _height;

    ST7789_PORT_CS_SELECT();
    ST7789_DATA(true);
    while (size--)
    {
        st7789_send_half_word(color);
    }
    ST7789_PORT_CS_DISELECT();
}